package server.utils;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
/**
 * Created by: Vincent Aumont
 * Copyright 2003 Infowave Software, Inc.
 */

/**
 * This class is responsible for retrieving the resources requested by
 * the desktop.
 *
 * We have a resources directory that contains all the portal resources.
 * Under this directory, we have (optiopnally) a directory per reseller where
 * each reseller can override the generic resource.
 *
 * Example:
 * --- resources/
 *     + logo.gif
 *     + scripts.js
 *     ---- reseller1
 *          + logo.gif
 *     ---- reseller2
 *          + logo.gif
 *
 * We don't want the desktop to know about our file structure or about the
 * fact that a reseller might want to customize some resources.
 *
 * When the desktop needs a resource (gifs, javascript, etc.) stored on the
 * portal, it uses urls following the pattern /x-res/<path to the resource>.
 * Example:
 * <img src="/x-res/logo.gif"/>
 * A filter traps such urls and map them to the actual resource url. It first
 * tries to locate the resource in the reseller's directory, and then in the
 * generic directory.
 *
 *
 */

public class ResourceManager {
    
    /** The class's logger */
    private static Log log = LogFactory.getLog(ResourceManager.class);
    
    /** The urls to the resoources (images, javascript, etc) generated by the
     * desktop must start with this prefix. e.g. <img src="/x-res/logo.gif">.
     * If this constants changes, the change must be made in the Filter section
     * of web.xml.
     */
    public static final String RESOURCES_PREFIX ="x-res/";
    
    /** The root of the resources directory. This should be a directory under
     *  our webapp's root directory  */
    public static final String RESOURCES_ROOT ="/resources/";
    
    /**
     * Computes the actual resource's uri from the requested resource.
     * For instance, if the requested resource is /x-res/logo.gif, the method
     * generates /resources/logo.gif or /resources/<reseller>/logo.gif.
     *
     * @param request the requested
     * @param includeReseller - whether to include the reseller's name in the path
     * @return the resource's uri.
     */
    private static String getResourceUri(HttpServletRequest request,
            String requestedResource,
            boolean includeReseller,
            boolean localized) {
        StringBuffer sb = new StringBuffer();
        //   SessionState state = WebUtil.getSessionState(request);
        
        // Start with our root directory
        sb.append(RESOURCES_ROOT);
        // Add the reseller directory if required
//        if (includeReseller && (state != null)) {
//            sb.append(state.getReseller().getName()).append("/");
//        }
//        // Add the requested resource.
        // Add the locale if required. We add the lcoale just before the last
        // extension.
//        if (localized && (state != null)) {
//            int lastExtensionIdx = requestedResource.lastIndexOf(".");
//            if (lastExtensionIdx != -1){
//                String main = requestedResource.substring(0,lastExtensionIdx);
//                String ext = requestedResource.substring(lastExtensionIdx,
//                        requestedResource.length());
//                sb.append(main).append("_").append(state.getLocale()).append(ext);
//            } else {
//                sb.append(requestedResource).append("_").append(state.getLocale());
//            }
//        } else {
        sb.append(requestedResource);
//        }
        return sb.toString();
    }
    
    
    /**
     * Extracts the requested static uri from a request.
     * For instance, if the request's url is
     * http://www.portal.com/html/action.do/x-res/logo.gif
     * the method returns: logo.gif
     *
     * @param request
     * @return
     */
    private static String getRequestedStaticResourceUri(HttpServletRequest request) {
        String uri = request.getRequestURI();
        try {
            uri = uri.substring(uri.indexOf(RESOURCES_PREFIX) +
                    RESOURCES_PREFIX.length());
        } catch(Exception e) {
            throw new IllegalArgumentException("Not a static resource uri: " + uri);
        }
        return uri;
    }
    
    /**
     * This method extracts the name of the requested static resource from the
     * request and returns the resource as a stream.
     *
     * @param request
     * @return the seource as a stream; null if not found.
     * @exception IllegalArgumentException if the request does not contain a uri
     * for a static resource.
     */
    public static InputStream getStaticResourceAsStream(HttpServletRequest request,
            boolean localized) {
        InputStream is = null;
        // extract the requested request from the request
        String uri = getRequestedStaticResourceUri(request);
        return getResourceAsStream(request,uri,localized);
    }
    
    /**
     * Returns a resource as a stream.
     * First, we look whether there is a reseller version of this resource, then
     * we try the generic resource.
     *
     * @param request
     * @return a stream if the resource was found, null otherwise.
     */
    public static InputStream getResourceAsStream(HttpServletRequest request,
            String resourceName,
            boolean localized) {
        InputStream is = null;
        ServletContext ctx;
        
        ctx =request.getSession().getServletContext();
        // first, try with to find this resource for our current reseller
        String resourcePath;
        
        resourcePath = getResourceUri(request,resourceName,true,localized);
        resourcePath = ctx.getRealPath(resourcePath);
        //log.debug("trying: " + resourcePath);
        try {
            is = new FileInputStream(resourcePath);
        } catch (FileNotFoundException e){
            //log.debug("not found: " + resourcePath);
        }
        
        // If not found, and the caller requested a localized resource, we try to
        // if we have a file without the locale extension for this resource
        if (is == null) {
            resourcePath = getResourceUri(request,resourceName,true,false);
            resourcePath = ctx.getRealPath(resourcePath);
            //log.debug("trying: " + resourcePath);
            try {
                is = new FileInputStream(resourcePath);
            } catch (FileNotFoundException e){
                //log.debug("not found: " + resourcePath);
            }
        }
        
        // If not found, we try without the reseller part
        if (is == null){
            resourcePath = getResourceUri(request,resourceName,false,localized);
            resourcePath = ctx.getRealPath(resourcePath);
            //log.debug("trying: " + resourcePath);
            try {
                is = new FileInputStream(resourcePath);
            } catch (FileNotFoundException e){
                //log.debug("not found: " + resourcePath);
            }
            // if not found and the caller required a localized resource, we try
            // without the locale extension
            resourcePath = getResourceUri(request,resourceName,false,false);
            resourcePath = ctx.getRealPath(resourcePath);
            //log.debug("trying: " + resourcePath);
            try {
                is = new FileInputStream(resourcePath);
            } catch (FileNotFoundException e){
                //log.debug("not found: " + resourcePath);
            }
        }
        return is;
    }
    
    
    public static byte[] getResourceAsByteArray(HttpServletRequest request,
            String resourceName,
            boolean localized) {
        byte[] bytes = null;
        InputStream is = null;
        try {
            is = getResourceAsStream(request,resourceName,localized);
            bytes = getStreamAsByteArray(is);
        } catch(IOException e){
            log.warn("Cannot retrieve resource: " + resourceName,e);
        } finally{
            if (is != null) {try{is.close();} catch(Exception e){}}
        }
        return bytes;
        
    }
    
    /**
     * Determaine whether this request is for a static resoource.
     *
     * @param request
     * @return
     */
    public static boolean isResourceRequest(HttpServletRequest request) {
        boolean isResource = false;
        String uri = request.getRequestURI();
        if (uri.indexOf(ResourceManager.RESOURCES_PREFIX) != -1){
            isResource = true;
        }
        return isResource;
    }
    
    /**
     * Reads a stream and returns its content as an array of bytes.
     * @param is - the stream to read,
     * @return
     */
    public static byte[]  getStreamAsByteArray(InputStream is)
    throws IOException {
        byte[] bytes = null;
        ByteArrayOutputStream baos = null;
        try {
            if (is != null) {
                baos = new ByteArrayOutputStream();
                byte[] buff = new byte[256];
                int nbBytes;
                while ((nbBytes = is.read(buff)) != -1) {
                    baos.write(buff,0,nbBytes);
                }
                bytes = baos.toByteArray();
            }
        } catch (IOException e){
            bytes = null;
            throw e;
        } finally{
            if (is != null) {try {is.close();} catch(Exception e) {}}
            if (baos != null) {try {baos.close();} catch(Exception e) {}}
        }
        return bytes;
    }
    
}
